From 2e362eafc7a22e007fddb4ee9c76dfffdbbf02b7 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 16 Dec 2015 19:48:30 +0100 Subject: [PATCH] cssnode: Redo first/last-child change tracking Invisible nodes don't change the first/last-child status of the nodes after/before them. That means we don't have to just check the state of the adjacent node when modifying this state, but all their siblings until we hit a visible node. The same way, a node is not the first child if it has no previous sibling, it is the first child if it has no previous visible sibling. This is important for caching in the global lookup cache. --- gtk/gtkcssnode.c | 72 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/gtk/gtkcssnode.c b/gtk/gtkcssnode.c index 738d1e9116..b129c01df2 100644 --- a/gtk/gtkcssnode.c +++ b/gtk/gtkcssnode.c @@ -253,6 +253,36 @@ gtk_css_node_finalize (GObject *object) G_OBJECT_CLASS (gtk_css_node_parent_class)->finalize (object); } +static gboolean +gtk_css_node_is_first_child (GtkCssNode *node) +{ + GtkCssNode *iter; + + for (iter = node->previous_sibling; + iter != NULL; + iter = iter->previous_sibling) + { + if (iter->visible) + return FALSE; + } + return TRUE; +} + +static gboolean +gtk_css_node_is_last_child (GtkCssNode *node) +{ + GtkCssNode *iter; + + for (iter = node->next_sibling; + iter != NULL; + iter = iter->next_sibling) + { + if (iter->visible) + return FALSE; + } + return TRUE; +} + #define UNPACK_DECLARATION(packed) ((GtkCssNodeDeclaration *) (GPOINTER_TO_SIZE (packed) & ~0x3)) #define UNPACK_FLAGS(packed) (GPOINTER_TO_SIZE (packed) & 0x3) #define PACK(decl, first_child, last_child) GSIZE_TO_POINTER (GPOINTER_TO_SIZE (decl) | ((first_child) ? 0x2 : 0) | ((last_child) ? 0x1 : 0)) @@ -292,8 +322,8 @@ lookup_in_global_parent_cache (GtkCssNode *node, style = g_hash_table_lookup (cache, PACK (decl, - gtk_css_node_get_previous_sibling (node) == NULL, - gtk_css_node_get_next_sibling (node) == NULL)); + gtk_css_node_is_first_child (node), + gtk_css_node_is_last_child (node))); return style; } @@ -376,8 +406,8 @@ store_in_global_parent_cache (GtkCssNode *node, g_hash_table_insert (cache, PACK (gtk_css_node_declaration_ref ((GtkCssNodeDeclaration *) decl), - gtk_css_node_get_previous_sibling (node) == NULL, - gtk_css_node_get_next_sibling (node) == NULL), + gtk_css_node_is_first_child (node), + gtk_css_node_is_last_child (node)), g_object_ref (style)); } @@ -1071,6 +1101,8 @@ void gtk_css_node_set_visible (GtkCssNode *cssnode, gboolean visible) { + GtkCssNode *iter; + if (cssnode->visible == visible) return; @@ -1094,14 +1126,34 @@ gtk_css_node_set_visible (GtkCssNode *cssnode, } if (cssnode->next_sibling) - gtk_css_node_invalidate (cssnode->next_sibling, GTK_CSS_CHANGE_ANY_SIBLING - | GTK_CSS_CHANGE_NTH_CHILD - | (cssnode->previous_sibling ? 0 : GTK_CSS_CHANGE_FIRST_CHILD)); - + { + gtk_css_node_invalidate (cssnode->next_sibling, GTK_CSS_CHANGE_ANY_SIBLING | GTK_CSS_CHANGE_NTH_CHILD); + if (gtk_css_node_is_first_child (cssnode)) + { + for (iter = cssnode->next_sibling; + iter != NULL; + iter = iter->next_sibling) + { + gtk_css_node_invalidate (iter, GTK_CSS_CHANGE_FIRST_CHILD); + if (iter->visible) + break; + } + } + } + if (cssnode->previous_sibling) { - if (cssnode->next_sibling) - gtk_css_node_invalidate (cssnode->previous_sibling, GTK_CSS_CHANGE_LAST_CHILD); + if (gtk_css_node_is_last_child (cssnode)) + { + for (iter = cssnode->previous_sibling; + iter != NULL; + iter = iter->previous_sibling) + { + gtk_css_node_invalidate (iter, GTK_CSS_CHANGE_LAST_CHILD); + if (iter->visible) + break; + } + } gtk_css_node_invalidate (cssnode->parent->first_child, GTK_CSS_CHANGE_NTH_LAST_CHILD); } } -- 2.30.2